<?php
/***
 * Candy框架 图像处理类	
 * 
 * $Author: 刘森 (fingerboy@qq.com) $
 * $Date: 2019-08-05 15:00:01 $   
 */
 
declare(strict_types=1);
namespace Candy\Extend;

defined('CANDY') OR die('You Are A Bad Guy. o_O???');

Class Image {
	protected $path;   //图片所在的路径
	
	/**
	 * 创建图像对象时传递图像的一个路径，默认值是框架的文件上传目录
	 *
	 * @param	string	$path	可以指定处理图片的路径
	 */
	public function __construct(string $path = '')
	{
		if($path == '')
			$path = G('C_UP_PATH');
		
		$this->path = $path;
	}
	
	/**
	 * 对指定的图像进行缩放
	 *
	 * @param	$name	是需要处理的图片名称
	 * @param	int	$width	缩放后的宽度
	 * @param	int	$height	缩放后的高度
	 * @param	string	$qz	是新图片的前缀
	 * @return	mixed		是缩放后的图片名称,失败返回false;
	 */
	public function thumb($name,int $width,int $height,string $qz = 'th_'): string
	{
		$path = '.';
		if(is_array($name))
			[$name, $path] = $name;
		
		//获取图片信息
		$imgInfo = $this->getInfo($name, $path);   
		//获取图片资源        
		$srcImg = $this->getImg($name, $imgInfo, $path);                
		//获取新图片尺寸
		$size = $this->getNewSize($name, $width, $height, $imgInfo);     
		//获取新的图片资源
		$newImg = $this->kidOfImage($srcImg, $size, $imgInfo);  
		//新的储存位置
		$newPath = G('C_UPCW_PATH') . ($path == '.' ? '' : '/' . trim($path, '/')) . '/';
		//返回新生成的缩略图的名称，以'th_'为前缀	
		return $this->createNewImage($newImg, $qz.$name, $imgInfo, $newPath);    
	}
	
	/** 
	* 为图片添加水印
	*
	* @param	string	$groundName	背景图片，即需要加水印的图片，暂只支持GIF,JPG,PNG格式； 
	* @param	string	$waterName	图片水印，即作为水印的图片，暂只支持GIF,JPG,PNG格式; 
	* @param	int	$waterPos	水印位置，有10种状态，0为随机位置； 
	* 					1为顶端居左，2为顶端居中，3为顶端居右； 
	* 					4为中部居左，5为中部居中，6为中部居右； 
	*					7为底端居左，8为底端居中，9为底端居右； 
	* @param	string	$qz		加水印后的图片的文件名在原文件名前面加上这个前缀，。
	* @return	mixed			是生成水印后的图片名称,失败返回false;
	*/ 
	public function waterMark(string $groundName,string $waterName,int $waterPos = 0,string $qz = 'wa_'): mixed
	{
		$curpath = rtrim($this->path,'/').'/';
		$dir = dirname($waterName);
		if($dir == '.'){
			$wpath = $curpath;
		}else{
			$wpath = $dir.'/';
			$waterName = basename($waterName);
		
		}
		
		if(file_exists($curpath.$groundName) && file_exists($wpath.$waterName)){
			$groundInfo = $this->getInfo($groundName);               //获取背景信息
			$waterInfo = $this->getInfo($waterName, $dir);                 //获取水印图片信息

			if(!$pos = $this->position($groundInfo, $waterInfo, $waterPos)){
				Debug::addMsg('<font color=\'red\'>水印不应该比背景图片小！</font>');
				return false;
			}

			$groundImg = $this->getImg($groundName, $groundInfo);    //获取背景图像资源
			$waterImg = $this->getImg($waterName, $waterInfo, $dir);       //获取水印图片资源	

			$groundImg = $this->copyImage($groundImg, $waterImg, $pos, $waterInfo);  //拷贝图像
			
			return $this->createNewImage($groundImg, $qz.$groundName, $groundInfo);
			
		}else{
			Debug::addMsg('<font color=\'red\'>图片或水印图片不存在！</font>');
			return false;
		}
	}
	
	/**
	 * 在一个大的背景图片中剪裁出指定区域的图片
	 *
	 * @param	$name	需要剪切的背景图片
	 * @param	int	$x	剪切图片左边开始的位置
	 * @param	int	$y	剪切图片顶部开始的位置
	 * @param	int	$width	图片剪裁的宽度
	 * @param	int	$height	图片剪裁的高度
	 * @param	string	$qz	是新图片的前缀
	 * @return	mixed		是裁剪后的图片名称,失败返回false;
	*/
	public function cut($name,int $x,int $y,int $width,int $height,string $qz = 'cu_'): mixed
	{
		$path = '.';
		if(is_array($name))
			[$name, $path] = $name;
		
		$imgInfo = $this->getInfo($name, $path);//获取图片信息
		
		if( (($x+$width) > $imgInfo['width']) || (($y+$height) > $imgInfo['height'])){
			Debug::addMsg('<font color=\'red\'>裁剪的位置超出了图片范围！</font>');
			return false;
		}
		
		$back = $this->getImg($name, $imgInfo);                          //获取图片资源      
	
		/* 创建一个可以保存裁剪后图片的资源 */
		$cutimg = imagecreatetruecolor($width, $height);
	
		/* 使用imagecopyresampled()函数对图片进行裁剪 */
		imagecopyresampled($cutimg, $back, 0, 0, $x, $y, $width, $height, $width, $height);
		
		imagedestroy($back);
	
		return $this->createNewImage($cutimg, $qz.$name, $imgInfo);    //返回新生成的缩略图的名称，以'cu_'为前缀
	}
	
	/**
	 * 在一个大的背景图片中剪裁出指定区域的图片
	 *
	 * @param	array	$groundInfo	背景图片信息
	 * @param	array	$waterInfo	水印图片信息
	 * @param	int		$waterPos	水印位置类型
	 * @return	array		位置
	*/
	private function position(array $groundInfo,array $waterInfo,int $waterPos): array
	{
		//需要加水印的图片的长度或宽度比水印还小，无法生成水印！
		if( ($groundInfo['width']<$waterInfo['width']) || ($groundInfo['height']<$waterInfo['height']) ){ 
			return false; 
		} 
		switch($waterPos){ 
			case 1://1为顶端居左 
				$posX = 0; 
				$posY = 0; 
				break; 
			case 2://2为顶端居中 
				$posX = ($groundInfo['width'] - $waterInfo['width']) / 2; 
				$posY = 0; 
				break; 
			case 3://3为顶端居右 
				$posX = $groundInfo['width'] - $waterInfo['width']; 
				$posY = 0; 
				break; 
			case 4://4为中部居左 
				$posX = 0; 
				$posY = ($groundInfo['height'] - $waterInfo['height']) / 2; 
				break; 
			case 5://5为中部居中 
				$posX = ($groundInfo['width'] - $waterInfo['width']) / 2; 
				$posY = ($groundInfo['height'] - $waterInfo['height']) / 2; 
				break; 
			case 6://6为中部居右 
				$posX = $groundInfo['width'] - $waterInfo['width']; 
				$posY = ($groundInfo['height'] - $waterInfo['height']) / 2; 
				break; 
			case 7://7为底端居左 
				$posX = 0; 
				$posY = $groundInfo['height'] - $waterInfo['height']; 
				break; 
			case 8://8为底端居中 
				$posX = ($groundInfo['width'] - $waterInfo['width']) / 2; 
				$posY = $groundInfo['height'] - $waterInfo['height']; 
				break; 
			case 9://9为底端居右 
				$posX = $groundInfo['width'] - $waterInfo['width']; 
				$posY = $groundInfo['height'] - $waterInfo['height']; 
				break; 
			case 0:
			default://随机 
				$posX = rand(0,($groundInfo['width'] - $waterInfo['width'])); 
				$posY = rand(0,($groundInfo['height'] - $waterInfo['height'])); 
				break; 
		}
		
		return ['posX'=>$posX, 'posY'=>$posY];
	}
	
	/**
	 * 获取图片的信息
	 */
	private function getInfo(string $name,string $path = '.'): array
	{
		$spath = $this->path . ($path == '.' ? '' : '/' . trim($path, '/')) . '/';
		
		$data = getimagesize($spath . $name);
		$imgInfo['width'] = $data[0];
		$imgInfo['height'] = $data[1];
		$imgInfo['type'] = $data[2];

		return $imgInfo;		
	}
	
	/**
	 * 创建图像资源 
	 */
	private function getImg(string $name,array $imgInfo,string $path = '.')
	{
		
		$spath = $this->path . ($path == '.' ? '' : '/' . trim($path, '/')) . '/';
		$srcPic = $spath.$name;
		
		switch ($imgInfo['type']){
			case 1:	//gif
				$img = imagecreatefromgif($srcPic);
				break;
			case 2:	//jpg
				$img = imagecreatefromjpeg($srcPic);
				break;
			case 3:	//png
				$img = imagecreatefrompng($srcPic);
				break;
			default:
				return false;
				break;
		}
		return $img;
	}
	
	/**
	 * 返回等比例缩放的图片宽度和高度，如果原图比缩放后的还小保持不变
	 */
	private function getNewSize(string $name,int $width,int $height,array $imgInfo): array
	{	
		$size['width'] = $imgInfo['width'];          //将原图片的宽度给数组中的$size['width']
		$size['height'] = $imgInfo['height'];        //将原图片的高度给数组中的$size['height']
		if($width < $imgInfo['width']){
			$size['width'] = $width;             //缩放的宽度如果比原图小才重新设置宽度
		}
		if($height < $imgInfo['height']){
			$size['height'] = $height;            //缩放的高度如果比原图小才重新设置高度
		}
		if($imgInfo['width']*$size['width'] > $imgInfo['height'] * $size['height']){
			$size['height'] = round($imgInfo['height']*$size['width']/$imgInfo['width']);
		}else{
			$size['width'] = round($imgInfo['width']*$size['height']/$imgInfo['height']);
		}
		return $size;
	}

	private function createNewImage($newImg, $newName, $imgInfo, $path = ''): string
	{
		$this->path = empty($path) ? $this->path : $path;
		switch ($imgInfo['type']){
	   		case 1:	//gif
				$result = imageGIF($newImg, $this->path.$newName);
				break;
			case 2:	//jpg
				$result = imageJPEG($newImg,$this->path.$newName);  
				break;
			case 3:	//png
				$result = imagePng($newImg, $this->path.$newName);  
				break;
		}
		imagedestroy($newImg);
		return $newName;
	}
	
	private function copyImage($groundImg, $waterImg, $pos, $waterInfo)
	{
		imagecopy($groundImg, $waterImg, $pos['posX'], $pos['posY'], 0, 0, $waterInfo['width'],$waterInfo['height']);
		imagedestroy($waterImg);
		return $groundImg;
	}
	
	private function kidOfImage($srcImg,array $size,array $imgInfo)
	{
		$newImg = imagecreatetruecolor($size['width'], $size['height']);		
		$otsc = imagecolortransparent($srcImg); //将某个颜色定义为透明色
		if( $otsc >= 0 && $otsc < imagecolorstotal($srcImg)){  //取得一幅图像的调色板中颜色的数目
	  		$transparentcolor = imagecolorsforindex( $srcImg, $otsc ); //取得某索引的颜色
	 		$newtransparentcolor = imagecolorallocate(
		   		$newImg,
		  		$transparentcolor['red'],
		   	    $transparentcolor['green'],
		   		$transparentcolor['blue']
	  		);

	  		imagefill( $newImg, 0, 0, $newtransparentcolor );
	  		imagecolortransparent( $newImg, $newtransparentcolor );
		}
		imagecopyresized($newImg, $srcImg, 0, 0, 0, 0, $size['width'], $size['height'], $imgInfo['width'], $imgInfo['height'] );
		imagedestroy($srcImg);
		return $newImg;
	}
}
